﻿using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Microsoft.AspNetCore.Mvc;
using shenghua.Authorization;
using shenghua.Common.CustomValueType;
using shenghua.Common.Dto;
using shenghua.Marketing.Coupons.Dto;
using shenghua.Member.Coupons;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace shenghua.Marketing.Coupons
{
    public class CouponAppService: shenghuaAppServiceBase, ICouponAppService
    {
        private readonly CouponManager _couponManager;
        private readonly MemberCouponManager _memberCouponManager;
        private readonly IRepository<Coupon> _couponRepository;
        private readonly IRepository<MemberCoupon> _memberCouponRepository;

        public CouponAppService(
            CouponManager couponManager,
            MemberCouponManager memberCouponManager,
            IRepository<Coupon> couponRepository,
            IRepository<MemberCoupon> memberCouponRepository
            )
        {
            _couponManager = couponManager;
            _memberCouponManager = memberCouponManager;
            _couponRepository = couponRepository;
            _memberCouponRepository = memberCouponRepository;
        }

        [AbpAuthorize(PermissionNames.CouponManagement)]
        public async Task<CouponDto> Create(CreateCouponDto input)
        {
            Coupon item = new Coupon
            {
                Name = input.Name,
                Amount = input.Amount,
                Condition = new CouponCondition
                {
                    MinAmount = new Money(input.MinAmount),
                    MinCount = input.MinCount
                },
                TimeLimit = new TimeLimit
                {
                    Begin = input.Begin,
                    End = input.End
                },
                AppliedCommodityIds = new ValueArray<int>(input.AppliedCommodityIds),
                TargetType = input.TargetType,
                RestCount = input.RestCount,
                IsInfinite = input.IsInfinite
            };
            await _couponManager.Add(item);
            return new CouponDto(item);
        }

        [AbpAuthorize(PermissionNames.CouponManagement)]
        public async Task<CouponDto> Update(UpdateCouponDto input)
        {
            Coupon item = await _couponManager.Get(input.Id);
            item.Name = input.Name;
            item.Amount = input.Amount;
            item.Condition.MinAmount = input.MinAmount;
            item.Condition.MinCount = input.MinCount;
            item.TimeLimit.Begin = input.Begin;
            item.TimeLimit.End = input.End;
            item.RestCount = input.RestCount;
            item.TargetType = input.TargetType;
            item.AppliedCommodityIds = new ValueArray<int>(input.AppliedCommodityIds);
            item.IsInfinite = input.IsInfinite;
            await _couponManager.Update(item);
            return new CouponDto(item);
        }

        [AbpAuthorize(PermissionNames.CouponManagement)]
        [HttpPost]
        public async Task Delete(EntityDto input)
        {
            await _couponManager.Delete(input.Id);
        }

        [AbpAuthorize(PermissionNames.CouponManagement)]
        public async Task<PagedResultDto<CouponDto>> AdminSearch(SearchCouponDto input)
        {
            var query = _couponRepository.GetAll();
            if (input.CommodityId != null)
            {
                query = query.Where(r => r.AppliedCommodityIds.Items.Contains((int)input.CommodityId));
            }

            if (!string.IsNullOrWhiteSpace(input.Status))
            {
                switch(input.Status)
                {
                    case "notbegin": query = query.Where(r => DateTime.Now < r.TimeLimit.Begin); break;
                    case "ongoing": query = query.Where(r => DateTime.Now >= r.TimeLimit.Begin && DateTime.Now <= r.TimeLimit.End); break;
                    case "ended": query = query.Where(r => DateTime.Now > r.TimeLimit.End); break;
                }
            }

            int totalCount = query.Count();
            var items = query.OrderByDescending(r => r.CreationTime).Skip(input.SkipCount).Take(input.MaxResultCount).ToList();

            var result = new PagedResultDto<CouponDto>
            {
                TotalCount = totalCount,
                Items = items.Select(r => new CouponDto(r)).ToList()
            };

            return result;
        }

        public async Task<PagedResultDto<CouponDto>> Search(SearchCouponDto input)
        {
            var query = _couponRepository.GetAll();
            if(input.CommodityId != null)
            {
                query = query.Where(r => 
                    (r.TargetType == CouponTargetType.Part && r.AppliedCommodityIds.Items.Contains((int)input.CommodityId))
                    || r.TargetType == CouponTargetType.All);
            }

            if (!string.IsNullOrWhiteSpace(input.Status))
            {
                switch (input.Status)
                {
                    case "notbegin": query = query.Where(r => DateTime.Now < r.TimeLimit.Begin); break;
                    case "ongoing": query = query.Where(r => DateTime.Now >= r.TimeLimit.Begin && DateTime.Now <= r.TimeLimit.End); break;
                    case "ended": query = query.Where(r => DateTime.Now > r.TimeLimit.End); break;
                }
            }

            int totalCount = query.Count();
            var items = query.OrderByDescending(r => r.CreationTime).Skip(input.SkipCount).Take(input.MaxResultCount).ToList();

            var result = new PagedResultDto<CouponDto>
            {
                TotalCount = totalCount,
                Items = items.Select(r => new CouponDto(r)).ToList()
            };

            var member = await GetCurrentMemberAsync(false);
            if(member != null)
            {
                foreach(var item in result.Items)
                {
                    item.IsReceived = _couponManager.IsReceived(MemberId, item.Id);
                }
            }

            return result;
        }

        [AbpAuthorize(PermissionNames.Member)]
        public async Task MemberReceiveCoupon(EntityDto input)
        {
            var item = await _couponManager.Get(input.Id);
            var member = await GetCurrentMemberAsync();
            await _couponManager.GrantCoupon(item, member);
        }

        [AbpAuthorize(PermissionNames.Member)]
        [HttpPost]
        public async Task<PagedResultDto<MemberCouponDto>> GetAllMemberCoupon(SearchMemberCouponDto input)
        {
            var query = _memberCouponRepository.GetAll().Where(r => r.MemberId == MemberId);

            if(input.Tag != null)
            {
                if (input.Tag == "unused")
                {
                    query = query.Where(r => r.Status == MemberCouponStatus.Unused && !r.TimeLimit.IsOverdue);
                }
                else if (input.Tag == "used")
                {
                    query = query.Where(r => r.Status != MemberCouponStatus.Unused);
                }
                else if (input.Tag == "overdue")
                {
                    query = query.Where(r => r.Status == MemberCouponStatus.Unused && r.TimeLimit.IsOverdue);
                }
            }

            int totalCount = query.Count();
            var items = query.OrderByDescending(r => r.CreationTime).Skip(input.SkipCount).Take(input.MaxResultCount).ToList();

            return new PagedResultDto<MemberCouponDto>
            {
                TotalCount = totalCount,
                Items = items.Select(r => new MemberCouponDto(r)).ToList()
            };
        }

        [AbpAuthorize(PermissionNames.Member)]
        public async Task DeleteMemberCoupon(EntityDto input)
        {
            await _couponManager.DeleteMemberCoupon(MemberId, input.Id);
        }
        
        [AbpAuthorize(PermissionNames.CouponManagement)]
        public async Task<PagedResultDto<MemberCouponDto>> SearchGrantRecords(SearchGrantRecordsDto input)
        {
            var query = _memberCouponRepository.GetAll().Where(r => r.CouponId == input.CouponId);

            int totalCount = query.Count();
            var items = query.OrderByDescending(r => r.CreationTime).Skip(input.SkipCount).Take(input.MaxResultCount).ToList();

            return new PagedResultDto<MemberCouponDto>
            {
                TotalCount = totalCount,
                Items = items.Select(r => new MemberCouponDto(r)).ToList()
            };
        }

        [AbpAuthorize(PermissionNames.CouponManagement)]
        [HttpPost]
        public async Task DeleteMemberCoupon(BatchIntIdDto input)
        {
            foreach(var id in input.Ids)
            {
                await _memberCouponManager.DeleteCoupon(id);
            }
        }
    }
}
